package com.secretopen.ruleengine.service.impl;

import cn.chenc.framework.core.text.Convert;
import cn.chenc.framework.core.util.JsonUtils;
import cn.hutool.core.util.IdUtil;
import com.secretopen.ruleengine.consts.Constants;
import com.secretopen.ruleengine.entity.*;
import com.secretopen.ruleengine.mapper.RuleDroolsMapper;
import com.secretopen.ruleengine.service.RuleConditionConfigService;
import com.secretopen.ruleengine.service.RuleDroolsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.drools.core.impl.InternalKnowledgeBase;
import org.drools.core.impl.KnowledgeBaseFactory;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
import org.kie.internal.builder.KnowledgeBuilder;
import org.kie.internal.builder.KnowledgeBuilderError;
import org.kie.internal.builder.KnowledgeBuilderErrors;
import org.kie.internal.builder.KnowledgeBuilderFactory;
import org.kie.internal.io.ResourceFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author secret
 * @since 2023-09-09
 */
@Slf4j
@Service
public class RuleDroolsServiceImpl extends ServiceImpl<RuleDroolsMapper, RuleDrools> implements RuleDroolsService {

    private static final Logger logger = LoggerFactory.getLogger(RuleDroolsServiceImpl.class);

    @Autowired
    private RuleConditionConfigService ruleConditionConfigService;

    @Override
    public void generationDrools(List<RuleApplyConfig> ruleApplyConfigs) {
        ArrayList ruleDrools = new ArrayList<RuleDrools>();
        for (RuleApplyConfig ruleApplyConfig : ruleApplyConfigs) {
            // 2.1 得到执行的所有条件id
//            String[] array = ruleApplyConfig.getExpressionIds().split(",");
//            Integer[] obj = (Integer[]) ConvertUtils.convert(array, Integer.class);
            Integer[] obj = Convert.toIntArray(",",ruleApplyConfig.getExpressionIds());
            List<Integer> idsList = Arrays.asList(obj);
            List<RuleConditionConfig> ruleConditionConfigs = ruleConditionConfigService.listByIds(idsList);
//            List<RuleConditionConfig> ruleConditionConfigs = ruleConditionConfigDao.selectByids(idsList);
            // 3.转换drools语法规则
            if (!ruleConditionConfigs.isEmpty()) {
                String droolsContent = ruleToDrl(ruleApplyConfig, ruleConditionConfigs);
                ruleDrools.add(
                        getRuleDrools(droolsContent, String.valueOf(ruleApplyConfig.getId()), "1"));
            }
        }
        // 批量插入
        this.saveBatch(ruleDrools);
    }

    /**
     * 转换drools语法，封装成可执行的drools
     *
     * @param ruleApplyConfig
     * @param ruleConditionConfigs
     * @return
     */
    @Override
    public String ruleToDrl(RuleApplyConfig ruleApplyConfig,
                           List<RuleConditionConfig> ruleConditionConfigs) {
        StringBuilder result = new StringBuilder();
        /* package部分 */
        result.append("package com.secretopen.ruledrools;\r\n");

        /* 导包部分 */
        result.append("import com.secretopen.ruleengine.entity.RuleResult;\r\n");
        result.append("import com.secretopen.ruleengine.entity.CaseInfoFact;\r\n");
        result.append("import cn.hutool.core.date.DateUnit;\r\n");
        result.append("import cn.hutool.core.date.DateUtil;\r\n");


        result.append("global java.util.List resultList;\r\n");
        result.append("\r\n");

        // 获取表达式
        String expression = ruleApplyConfig.getExpression();

        // 替换成drools语法
        for (RuleConditionConfig ruleConditionConfig : ruleConditionConfigs) {
            if (expression.contains(ruleConditionConfig.getId().toString())) {
                StringBuffer expressValue = new StringBuffer();
                if(Constants.FIELD_TYPE_CUSTOM.equals(ruleConditionConfig.getFieldCode())) {
                    expressValue.append(" "+ruleConditionConfig.getFieldValue()+" ");
                    expression = expression.replace(ruleConditionConfig.getId().toString(), expressValue);
                    continue;
                }
                if (ruleConditionConfig.getFieldValue().contains("and")) {
                    String[] arrays = ruleConditionConfig.getFieldValue().split("and");
                    expressValue.append("(");
                    for (int i = 0; i < arrays.length; i++) {
                        expressValue.append(ruleConditionConfig.getFieldCode());
                        expressValue.append(" " + ruleConditionConfig.getConditionCode() + " ");
                        if(Constants.FIELD_TYPE_STRING.equals(ruleConditionConfig.getFieldType())) {
                            expressValue.append("\"").append(arrays[i]).append("\"");
                        }else if(Constants.FIELD_TYPE_DECIMAL.equals(ruleConditionConfig.getFieldType())) {
                            expressValue.append(arrays[i]);
                        }else if(Constants.FIELD_TYPE_OTHER.equals(ruleConditionConfig.getFieldType())) {
                            expressValue.append(arrays[i]);
                        }else {
                            expressValue.append(arrays[i]);
                        }

                        if (i < (arrays.length - 1)) {
                            expressValue.append(" && ");
                        }
                    }
                    expressValue.append(")");
                }else if (ruleConditionConfig.getFieldValue().contains("or"))  {
                    String[] arrays = ruleConditionConfig.getFieldValue().split("or");
                    expressValue.append("(");
                    for (int i = 0; i < arrays.length; i++) {
                        expressValue.append(ruleConditionConfig.getFieldCode());
                        expressValue.append(" " + ruleConditionConfig.getConditionCode() + " ");
                        if(Constants.FIELD_TYPE_STRING.equals(ruleConditionConfig.getFieldType())) {
                            expressValue.append("\"").append(arrays[i]).append("\"");
                        }else if(Constants.FIELD_TYPE_DECIMAL.equals(ruleConditionConfig.getFieldType())) {
                            expressValue.append(arrays[i]);
                        }else if(Constants.FIELD_TYPE_OTHER.equals(ruleConditionConfig.getFieldType())) {
                            expressValue.append(arrays[i]);
                        }else {
                            expressValue.append(arrays[i]);
                        }

                        if (i < (arrays.length - 1)) {
                            expressValue.append(" || ");
                        }
                    }
                    expressValue.append(")");
                }else {
                    expressValue.append(ruleConditionConfig.getFieldCode());
                    expressValue.append(" " + ruleConditionConfig.getConditionCode() + " ");
                    if(Constants.FIELD_TYPE_STRING.equals(ruleConditionConfig.getFieldType())) {
                        expressValue.append("\"").append(ruleConditionConfig.getFieldValue()).append("\"");
                    }else if(Constants.FIELD_TYPE_DECIMAL.equals(ruleConditionConfig.getFieldType())) {
                        expressValue.append(ruleConditionConfig.getFieldValue());
                    }else if(Constants.FIELD_TYPE_OTHER.equals(ruleConditionConfig.getFieldType())) {
                        expressValue.append(ruleConditionConfig.getFieldValue());
                    }else {
                        expressValue.append(ruleConditionConfig.getFieldValue());
                    }
                }

                expression = expression.replace(ruleConditionConfig.getId().toString(), expressValue);
            }
        }

        /* 规则申明部分 */
        result.append("rule \"" + ruleApplyConfig.getId() + "_" + ruleApplyConfig.getTypeName() + "\"\r\n");

        /* 规则属性部分 */

        /* 规则条件部分 */
        result.append("\twhen\r\n");
        result.append("\t\t$caseInfoFact : CaseInfoFact(" + expression + ");\r\n");

        /* 规则结果部分 */
        result.append("\tthen\r\n");
        result.append("\t\tRuleResult ruleResult=new RuleResult();\r\n");
        result.append("\t\truleResult.setCaseNo($caseInfoFact.getCaseNo()); \r\n");
        result.append("\t\truleResult.setForeignId(\"" + ruleApplyConfig.getId() + "\");\r\n");
        result.append("\t\truleResult.setRuleKey(\"" + ruleApplyConfig.getTypeCode() + "\");\r\n");
        result.append("\t\truleResult.setRuleName(\"" + ruleApplyConfig.getTypeName() + "\");\r\n");

        result.append("\t\tresultList.add(ruleResult);\r\n");

        /* 规则结束 */
        result.append("end\r\n");
        return result.toString();
    }

    private RuleDrools getRuleDrools(String droolsContent, String foreignId, String droolsStatus) {
        RuleDrools ruleDrools = new RuleDrools();
        ruleDrools.setBusinessId(IdUtil.simpleUUID());
        ruleDrools.setContent(droolsContent);
        ruleDrools.setInsertTime(new Date());
        ruleDrools.setUpdateTime(new Date());
        ruleDrools.setForeignId(foreignId);
        ruleDrools.setDroolsStatus(droolsStatus);
        ruleDrools.setDroolsType("1");
        return ruleDrools;
    }

    /**
     * 运行规则
     *
     * @param ruleDrools
     */
    @SuppressWarnings("unchecked")
    @Override
    public List<RuleResult> executeDrools(List<RuleDrools> ruleDrools, CaseInfoFact caseInfoFact) {
        // 4.执行规则
        int ruleFiredCount = 0;
        List<RuleResult> results = new ArrayList<RuleResult>();
        if (!ruleDrools.isEmpty()) {
            KieSession kSession = null;
            try {
                logger.info("--------------------开始执行规则---------------------");
//				String format = getDictNameValue("CHARSET_FORMAT", "FORMAT"); // utf-8（本地用）,GBK(生产，测试用)
                KnowledgeBuilder kb = KnowledgeBuilderFactory.newKnowledgeBuilder();
                // 装入规则，可以装入多个
                for (RuleDrools ruleDrools2 : ruleDrools) {
                    kb.add(ResourceFactory.newByteArrayResource(ruleDrools2.getContent().getBytes()),
                            ResourceType.DRL);
                }



                KnowledgeBuilderErrors errors = kb.getErrors();
                if (errors.size() > 0) {
                    for (KnowledgeBuilderError error: errors) {
                        logger.error(error.getMessage());
                    }
                    throw new IllegalArgumentException("Could not parse knowledge.");
                }
//				for (KnowledgeBuilderError error : errors) {
//					logger.error("装入规则出错:", error);
//				}

                InternalKnowledgeBase kBase = KnowledgeBaseFactory.newKnowledgeBase();
                kBase.addPackages(kb.getKnowledgePackages());

                kSession = kBase.newKieSession();
                List<RuleResult> list = new ArrayList<>();
                RuleResult ruleResult = new RuleResult();
                kSession.setGlobal("resultList", list);
                kSession.insert(caseInfoFact);
                kSession.insert(ruleResult);
                ruleFiredCount = kSession.fireAllRules();
                logger.info("--------------------结束执行规则---------------------");
                logger.info("该报案号【" + caseInfoFact.getCaseNo() + "】已触发了" + ruleFiredCount + "条规则");
                results = (List<RuleResult>) kSession.getGlobal("resultList");
                logger.info("查看执行结果：" + JsonUtils.objectToJson(results));

            } catch (Exception e) {
                logger.error("执行规则出错。。。", e);
            } finally {
                if (kSession != null) {
                    kSession.dispose();
                }
            }

        }
        return results;
    }
}
